# -*- coding: utf-8 -*-
import ftplib
from utils.log_utils import get_logger
from typing import Optional, List

logger = get_logger("logProcess")
"""

    ftp相关工具

"""


# ftp
class FTPClient:
    """
    A simple FTP client wrapper for connecting, uploading, downloading, and managing files on an FTP server.

    Usage:
        with FTPClient(ip, username, password) as ftp:
            ftp.upload_file('local.txt', 'remote.txt')
    """

    def __init__(
            self,
            host: str,
            username: str,
            password: str,
            port: int = 21,
            timeout: int = 30
    ) -> None:
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.timeout = timeout
        self._ftp: Optional[ftplib.FTP] = None

    def __enter__(self) -> ftplib.FTP:
        return self.connect()

    def __exit__(
            self,
            exc_type,
            exc_value,
            traceback
    ) -> None:
        self.disconnect()

    def connect(self) -> ftplib.FTP:
        """Connects to the FTP server and logs in."""
        if self._ftp:
            return self._ftp

        try:
            ftp = ftplib.FTP()
            ftp.connect(self.host, self.port, timeout=self.timeout)
            ftp.encoding = 'utf-8'
            ftp.login(self.username, self.password)
            self._ftp = ftp
            logger.info(f"Connected to FTP: {self.host}:{self.port}")
            return ftp
        except ftplib.all_errors as e:
            logger.error(f"FTP connection/login failed: {e}")
            raise

    def disconnect(self) -> None:
        """Quits the FTP session if connected."""
        if self._ftp:
            try:
                self._ftp.quit()
                logger.info(f"Disconnected from FTP: {self.host}:{self.port}")
            except ftplib.all_errors as e:
                logger.warning(f"Error on FTP quit: {e}")
            finally:
                self._ftp = None

    def list_files(self, path: str = '') -> List[str]:
        """Lists files in the given directory."""
        ftp = self.connect()
        try:
            return ftp.nlst(path)
        except ftplib.error_perm as e:
            logger.error(f"Permission error listing '{path}': {e}")
            return []

    def upload_file(
            self,
            local_filepath: str,
            remote_filepath: Optional[str] = None
    ) -> None:
        """Uploads a local file to the FTP server."""
        ftp = self.connect()
        remote = remote_filepath or local_filepath
        try:
            with open(local_filepath, 'rb') as f:
                ftp.storbinary(f'STOR {remote}', f)
            logger.info(f"Uploaded '{local_filepath}' to '{remote}'")
        except (IOError, ftplib.all_errors) as e:
            logger.error(f"Upload failed for '{local_filepath}': {e}")
            raise

    def download_file(
            self,
            remote_filepath: str,
            local_filepath: Optional[str] = None
    ) -> None:
        """Downloads a file from the FTP server to local."""
        ftp = self.connect()
        local = local_filepath or remote_filepath
        try:
            with open(local, 'wb') as f:
                ftp.retrbinary(f'RETR {remote_filepath}', f.write)
            logger.info(f"Downloaded '{remote_filepath}' to '{local}'")
        except (IOError, ftplib.all_errors) as e:
            logger.error(f"Download failed for '{remote_filepath}': {e}")
            raise

    def delete_file(self, remote_filepath: str) -> None:
        """Deletes a file on the FTP server."""
        ftp = self.connect()
        try:
            ftp.delete(remote_filepath)
            logger.info(f"Deleted remote file '{remote_filepath}'")
        except ftplib.all_errors as e:
            logger.error(f"Delete failed for '{remote_filepath}': {e}")
            raise

    def change_directory(self, path: str) -> None:
        """Changes working directory on the FTP server."""
        ftp = self.connect()
        try:
            ftp.cwd(path)
            logger.info(f"Changed directory to '{path}'")
        except ftplib.error_perm as e:
            logger.error(f"Change directory failed for '{path}': {e}")
            raise

    def make_directory(self, path: str) -> None:
        """Creates a new directory on the FTP server."""
        ftp = self.connect()
        try:
            ftp.mkd(path)
            logger.info(f"Created directory '{path}'")
        except ftplib.all_errors as e:
            logger.error(f"Make directory failed for '{path}': {e}")
            raise
